<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>羊了个羊html版本</title>
  <script src="../static/js/vue.global.js"></script>
  <style>
    .flex{
      display: flex;
      justify-content: center;
    }
    .cover{
      pointer-events: none;
      box-shadow: 0 3px 0 0 #999, 0 8px 0 0 #666, 0 8px 0 2px #000, 0 0 0 2px #000;
    }
  </style>
</head>
<body>
<div id="app">
  <div class="step step1" v-if="step === 1">
    <!-- 游戏配置 -->
    <div class="option-list">
      <div class="option flex" v-for="opt in options" :key="opt.name">
        <div class="label">{{opt.label}}：</div>
        <input v-model="option[opt.name]" type="range" :min="opt.min" :max="opt.max">
        <div class="txt">{{option[opt.name]}}</div>
      </div>
    </div>
    <div class="btn-list flex">
      <button @click="startGame">开始游戏</button>
    </div>
  </div>
  <div class="step step2" v-else-if="step === 2">
    <!-- 游戏中 -->
    <!-- 需要消除的list -->
    <div v-for="card in cardList" :key="card.key" :class="{'cover': card.cover}" :style="card.style" @click="clickCard(card)">
      {{card.content}}
    </div>

    <!-- 抽离的list -->
    <div v-for="card in detachList" :key="card.key" :style="card.style" @click="clickCard(card)">
      {{card.content}}
    </div>

    <!-- 已选择的list -->
    <div v-for="card in chosedList" :key="card.key"  :style="card.style">
      {{card.content}}
    </div>

    <!-- 已消除的list -->
    <div v-for="card in clearList" :key="card.key" :style="card.style">
      {{card.content}}
    </div>
  </div>
  <div class="step step3" v-else>
    <!-- 游戏结束 -->
    <div class="button-list">
      <button @click="replay">重来</button>
    </div>
  </div>
</div>
<script>
  const { createApp } = Vue;

  // 声明卡片类
  class Card {
    // w-卡片宽，h-卡片高，colorType-卡片可选的颜色类型，contentType-卡片内容类型
    static w = 20;
    static h = 21;
    static colorType = {
      1: {background: '#FFB7DD'},
      2: {background: '#FFCCCC'},
      3: {background: '#FFC8B4'},
      4: {background: '#FFDDAA'},
      5: {background: '#FFEE99'},
      6: {background: '#FFFFBB'},
      7: {background: '#EEFFBB'},
      8: {background: '#CCFF99'},
      9: {background: '#99FF99'},
      10: {background: '#BBFFEE'},
      11: {background: '#AAFFEE'},
      12: {background: '#99FFFF'},
      13: {background: '#CCEEFF'},
      14: {background: '#CCDDFF'}
    };
    static contentType = {
      1: '🥕',
      2: '✂️',
      3: '🥦',
      4: '🥛',
      5: '🌊',
      6: '🧤',
      7: '🧵',
      8: '🌱',
      9: '🔨',
      10: '🌽',
      11: '🌾',
      12: '🐑',
      13: '🪵',
      14: '🔥'
    };

    // 传入坐标（x, y, z）以及卡片类型key
    constructor({x, y, z, key}) {
      this.x = x;
      this.y = y;
      this.z = z;
      this.key = key;
      this.val = key;
      this.style = {
        top: `${y * Card.h}px`,
        left: `${x * Card.w}px`,
        width: `${2 * Card.w - 2}px`,
        height: `${2 * Card.h - 8}px`,
      }
    }
    setValue(val) {
      this.val = val;
      this.content = this.contentType[val];
      Object.assign(this.style, this.colorType[val]);
    }

  }
  createApp({
    data() {
      return {
        step: 1, // 当前步骤，1-开始游戏前设置难度，2-进行游戏/游戏中，3-游戏结束：重来
        win: false, // 输赢状态
        options: [
          {
            name: 'row',
            label: '行数',
            min: 4,
            max: 10,
          },
          {
            name: 'column',
            label: '列数',
            min: 4,
            max: 10,
          },
          {
            name: 'density',
            label: '难度',
            min: 1,
            max: 10,
          },
          {
            name: 'cardType',
            label: '卡片类型',
            min: 4,
            max: 14
          }
        ],
        option: {
          row: 4, // 行数
          column: 4, // 列数
          level: 4, // 层级
          density: 1, // 难度等级：实际就是卡片密度
          cardType: 5, // 卡片类型
        },

        cardLayout: [],
        cardList: [],
        chosedList: [],
        detachList: [],
        peddingList: [], // 等待列表
        clearList: [], // 清除列表
        saveList: [], // 抽离3个卡片列表
        calcValueList: [], // 暂存等待列表中各类型卡片已有的数据
        maxWidth: 0,
        maxHeight: 0,

        // 工具：实现暂存抽离3个卡片，随机重排
        tools: {
          save: true,
          rand: true
        },
        timer: null, // 计时器





      }
    },
    methods: {
      startGame() {
        this.step = 2;
        this.initGame();
      },
      initGame() {
        this.setCardLayout();
        this.penddingList = [];
        this.clearList = [];
        this.saveList = [];
        this.tools.save = true;
        this.tools.rand = true;
      },
      // 生成布局
      setCardLayout() {
        this.maxWidth = this.option.row * 2;
        this.maxHeight = this.option.column * 2;
        this.cardLayout = new Array(this.option.level); // 生成层级

        let key = 0;

        // 生成网格
        // [
        //  [0, 0, 0, 0, 0, 0]
        //  [0, 0, 0, 0, 0, 0]
        //  [0, 0, 0, 0, 0, 0]
        //  [0, 0, 0, 0, 0, 0]
        //  [0, 0, 0, 0, 0, 0]
        // ]
        for(let z = 0; z<this.option.level; z++) {
          this.cardLayout[z] = new Array(this.maxHeight);
          for(let y = 0; y<this.maxHeight; y++) {
            this.cardLayout[z][y] = new Array(this.maxWidth).fill(0);
          }
        }

        // 先考虑同一层该怎么放置卡片
        // [ 0, 0, 0, 0, 0, 0 ]
        // [ 0, 0, 0, 0, 0, 0 ]
        // [ 0, 0, 1, 0, 0, 0 ]
        // [ 0, 0, 0, 0, 0, 0 ]
        // [ 0, 0, 0, 0, 0, 0 ]
        // [ 0, 0, 0, 0, 0, 0 ]
        // 同一层，一张卡片如果在中间，周围有8种放置方法
        // 类型再拆分下：
        // 在已有的卡片的右边，那么是：右上，右边，右下，当x>0,



        // 插入卡片到cardLayout和cardList
        for(let z = 0; z<this.option.level; z++) {
          const shrink = Math.floor((z - this.option.level) / 3);
          for(let y = shrink; y<this.option.level - shrink; y++) {
            const mid = Math.ceil((this.maxWidth - shrink) / 2);
            for(let x = shrink; x<mid; x++) {
              let canSetCard = true;
              if (
                (y>0 && this.cardLayout[z][y-1][x]) || // 上面不能有卡片
                (x>0 && this.cardLayout[z][y][x-1]) || // 左边不能有卡片
                (x>0 && y>0 && this.cardLayout[z][y-1][x-1]) || // 左上不能有卡片
                (y>0 && this.cardLayout[z][y-1][x+1]) || // 右上不能有卡片
                (z>0 && this.cardLayout[z-1][y][x]) ||   // 正底不能有卡片
                Math.random(1, 10) >= this.option.density // 随机数大于难度值不能有卡片
              ) {
                canSetCard = false;
              }

              if (canSetCard) {
                key++;
                const card = new Card({
                  x: x,
                  y: y,
                  z: z,
                  k: key
                });
                this.cardLayout[z][y][x] = card;
                this.cardList.push(card);

                // 对称布局，如果x小于中间，那么在另外一边也插入一个卡片
                if (x<mid) {
                  key++;
                  const card = new Card({
                    x: this.maxWidth - x,
                    y: y,
                    z: z,
                    k: key
                  });
                  this.cardLayout[z][y][x] = card;
                  this.cardList.push(card);
                }
              }
            }
          }
        }

        //
        this.cardList.reverse();
        for(let i = 1; i<key % 3; i++) {
          const clearCard = this.cardList.pop();
          cardLayout[clearCard.z][clearCard.y][clearCard.x] = 0;
        }
        this.cardList.reverse();
      },
      // 设置卡片值
      setCardValue() {
        const maxCardType = this.option.cardType;
        const valStack = new Array(maxCardType);
        this.calcValueList = new Array(maxCardType + 1).fill(0);
        this.cardList.forEach(card => {
          const val = Math.ceil(Math.random() * maxCardType);
          if (valStack[val]) {
            valStack[val].push(card);
            if (valStack[val].length === 3) {
              valStack[val].forEach(i => {
                i.setValue(val)
              });
              valStack[val] = null;
            }
          } else {
            valStack[val] = [card];
          }
        });
        let count = 2;
        valStack.forEach(list => {
          list && list.forEach(i => {
            count++;
            i.setValue(Math.floor(count / 3))
          })
        })
      },
      // 计算遮挡
      calcCover() {

      },
      clickCard(card) {

      },

      // 重来
      replay() {
        this.startGame()
      }
    }
  }).mount('#app')
</script>
</body>
</html>
